package me.zhyd.oauth.request

import com.alibaba.fastjson.JSONObject
import me.zhyd.oauth.cache.AuthStateCache
import me.zhyd.oauth.config.AuthConfig
import me.zhyd.oauth.config.AuthSource
import me.zhyd.oauth.enums.AuthResponseStatus
import me.zhyd.oauth.enums.AuthUserGender
import me.zhyd.oauth.exception.AuthException
import me.zhyd.oauth.model.AuthCallback
import me.zhyd.oauth.model.AuthToken
import me.zhyd.oauth.model.AuthUser
import me.zhyd.oauth.utils.HttpUtils
import me.zhyd.oauth.utils.StringUtils
import me.zhyd.oauth.utils.UrlBuilder

/**
 * <p>
 * 企业微信登录父类
 * </p>
 *
 * @author LikeYouDo
 */
abstract class AbstractAuthWeChatEnterpriseRequest : AuthDefaultRequest {

    constructor(config: AuthConfig, source: AuthSource) : super(config, source)

    constructor(config: AuthConfig, source: AuthSource, authStateCache: AuthStateCache) : super(
        config,
        source,
        authStateCache
    )

    override fun getAccessToken(authCallback: AuthCallback): AuthToken? {
        val response = doGetAuthorizationCode(accessTokenUrl(null))

        val obj = this.checkResponse(response)

        return AuthToken.builder()
            .accessToken(obj.getString("access_token"))
            .expireIn(obj.getIntValue("expires_in"))
            .code(authCallback.code)
            .build()
    }

    override fun getUserInfo(authToken: AuthToken): AuthUser? {
        val response = doGetUserInfo(authToken)
        val obj = this.checkResponse(response)

        // 返回 OpenId 或其他，均代表非当前企业用户，不支持
        // https://github.com/justauth/JustAuth/issues/227 修复bug
        if (!obj.containsKey("userid")) {
            throw AuthException(AuthResponseStatus.UNIDENTIFIED_PLATFORM, source)
        }
        val userId = obj.getString("userid")
        val userTicket = obj.getString("user_ticket")
        val userDetail = getUserDetail(authToken.accessToken, userId, userTicket)

        return AuthUser.builder()
            .rawUserInfo(userDetail)
            .username(userDetail.getString("name"))
            .nickname(userDetail.getString("alias"))
            .avatar(userDetail.getString("avatar"))
            .location(userDetail.getString("address"))
            .email(userDetail.getString("email"))
            .uuid(userId)
            .gender(AuthUserGender.getWechatRealGender(userDetail.getString("gender")))
            .token(authToken)
            .source(source.toString())
            .build()
    }

    /**
     * 校验请求结果
     *
     * @param response 请求结果
     * @return 如果请求结果正常，则返回JSONObject
     */
    private fun checkResponse(response: String?): JSONObject {
        val obj = JSONObject.parseObject(response)

        if (obj.containsKey("errcode") && obj.getIntValue("errcode") != 0) {
            throw AuthException(obj.getString("errmsg"), source)
        }

        return obj
    }


    /**
     * 返回获取accessToken的url
     *
     * @param code 授权码
     * @return 返回获取accessToken的url
     */
    override fun accessTokenUrl(code: String?): String? {
        return UrlBuilder.fromBaseUrl(source.accessToken())
            .queryParam("corpid", config.clientId)
            .queryParam("corpsecret", config.clientSecret)
            .build()
    }

    /**
     * 返回获取userInfo的url
     *
     * @param authToken 用户授权后的token
     * @return 返回获取userInfo的url
     */
    override fun userInfoUrl(authToken: AuthToken): String? {
        return UrlBuilder.fromBaseUrl(source.userInfo())
            .queryParam("access_token", authToken.accessToken)
            .queryParam("code", authToken.code)
            .build()
    }

    /**
     * 用户详情
     *
     * @param accessToken accessToken
     * @param userId      企业内用户id
     * @param userTicket  成员票据，用于获取用户信息或敏感信息
     * @return 用户详情
     */
    private fun getUserDetail(accessToken: String?, userId: String?, userTicket: String?): JSONObject {
        // 用户基础信息
        val userInfoUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/user/get")
            .queryParam("access_token", accessToken)
            .queryParam("userid", userId)
            .build()
        val userInfoResponse = HttpUtils(config.httpConfig).get(userInfoUrl).body
        val userInfo = checkResponse(userInfoResponse)

        // 用户敏感信息
        if (StringUtils.isNotEmpty(userTicket)) {
            val userDetailUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail")
                .queryParam("access_token", accessToken)
                .build()
            val param = JSONObject()
            param["user_ticket"] = userTicket
            val userDetailResponse =
                HttpUtils(config.httpConfig).post(userDetailUrl, param.toJSONString()).body
            val userDetail = checkResponse(userDetailResponse)

            userInfo.putAll(userDetail)
        }
        return userInfo
    }

}
